package com.yuxi.pubInter;


import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import com.yuxi.common.SkMap;
import com.yuxi.common.StringUtil;
import com.yuxi.common.constant.PageKeyEnum;
import com.yuxi.common.enums.WhetherEnum;
import com.yuxi.pubInter.exception.DaoException;
import com.yuxi.pubInter.exception.DaoExceptionEnum;
import com.yuxi.pubInter.exception.SkException;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author sunke
 * @Date 2021-02-26 14:00:10
 * @description
 */
@Slf4j
public abstract class AbstractBaseService<T extends BaseIdDoMain<KeyType>, TS extends BaseSearch, KeyType> extends AbstractBaseFindService<T, TS, KeyType> {

    @Override
    public abstract IBaseDao<T, TS, KeyType> getDao();


    public void afterInsert(T obj) throws SkException {
        if (StringUtil.isNullOrEmpty(obj)) {
            return;
        }
        after(obj.getId());
    }

    public void beforeInsert(T obj) throws SkException {


    }

    public void afterDelete(KeyType id) throws SkException {
        after(id);
    }

    /**
     * 更新后操作
     *
     * @param obj
     */
    public void afterUpdate(T obj) throws SkException {
        if (StringUtil.isNullOrEmpty(obj)) {
            return;
        }
        after(obj.getId());
    }

    public void after(KeyType id) throws SkException {

    }

    public void beforeLogicDelete(KeyType id) throws SkException {

    }

    public void afterLogicDelete(KeyType id) throws SkException {


    }

    public void beforeDelete(KeyType id) throws SkException {

    }

    public void beforeUpdate(T obj) throws SkException {

    }


    @Transactional(rollbackFor = Exception.class)
    public T insert(T obj) throws SkException {

        beforeInsert(obj);

        int result = getDao().insert(obj);
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_INSERT_ERROR);
        }
        afterInsert(obj);
        return obj;
    }

    @Transactional(rollbackFor = Exception.class)
    public int delete(KeyType id) throws SkException {
        beforeDelete(id);
        int result = getDao().delete(id);
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_DEL_ERROR);
        }
        afterDelete(id);
        return result;
    }

    /**
     * 逻辑删除
     *
     * @param id
     * @return
     * @throws SkException
     */
    @Transactional(rollbackFor = Exception.class)
    public int logicDelete(KeyType id) throws SkException {
        beforeLogicDelete(id);
        int result = getDao().logicDelete(id);
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_DEL_ERROR);
        }
        afterLogicDelete(id);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public int delete(T obj) throws SkException {
        if (obj == null) {
            throw new DaoException(DaoExceptionEnum.DAO_GET_ERROR);
        }

        beforeDelete(obj.getId());
        int result = getDao().delete(obj.getId());
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_DEL_ERROR);
        }
        afterDelete(obj.getId());
        return result;
    }


    public int batchDelete(List<KeyType> list) throws SkException {
        int result = getDao().batchDelete(list);
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_DEL_ERROR);
        }
        return result;
    }

    public int batchDeleteByList(List<T> list) throws SkException {

        if (StringUtil.isObjEmpty(list)) {
            return 0;
        }


        int result = getDao().batchDelete(list.stream().map(t -> {
            if (t instanceof BaseIdDoMain) {
                return t.getId();
            }
            return null;
        }).collect(Collectors.toList()));

        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_DEL_ERROR);
        }
        return result;
    }


    /**
     * 逻辑删除
     *
     * @param ts
     * @return
     * @throws SkException
     */
    public int delLogicBySearch(TS ts) throws SkException {
        try {
            Class<T> tClass = getDomainClass();
            String delField = (String) tClass.getField("DEL_FLAG").get("DEL_FLAG");
            return updateDataBySearch(SkMap.getInstance().addObjToMap(delField, WhetherEnum.YES.getValue()), ts) ? 1 : 0;
        } catch (Exception e) {

        }
        return 0;
    }


    /**
     * 逻辑删除
     *
     * @param id
     * @return
     * @throws SkException
     */
    public int delLogicById(KeyType id) throws SkException {

        if (StringUtil.isNullOrEmpty(id)) {
            return 0;
        }
        try {
            Class<T> tClass = getDomainClass();
            String delField = (String) tClass.getField("DEL_FLAG").get("DEL_FLAG");
            return updateDataById(SkMap.getInstance().addObjToMap(delField, WhetherEnum.YES.getValue()), id) ? 1 : 0;
        } catch (Exception e) {

        }
        return 0;
    }


    @Transactional(rollbackFor = Exception.class)
    public T update(T obj) throws SkException {
        beforeUpdate(obj);
        int result = getDao().update(obj);
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_UPDATE_ERROR);
        }
        afterUpdate(obj);
        return obj;
    }


    /**
     * 更新，条件是根据主键+version去查询，目标防止，更新的时候，别人已更新这条记录，
     *
     * @param obj
     * @param versionMark
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public T updateByVersion(T obj, Integer versionMark) throws SkException {
        beforeUpdate(obj);
        if (obj instanceof BaseTimeDoMain) {
            ((BaseTimeDoMain) obj).setVersionMark(versionMark);
        }
        int result = getDao().updateByVersion(obj);
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_UPDATE_ERROR);
        }
        afterUpdate(obj);
        return obj;
    }


    /**
     * 更新，条件是根据主键+更新时间去查询，目标防止，更新的时候，别人已更新这条记录，
     *
     * @param obj
     * @param updateTimeMark
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public T updateByUpdateTime(T obj, Date updateTimeMark) throws SkException {
        beforeUpdate(obj);
        if (obj instanceof BaseTimeDoMain) {
            ((BaseTimeDoMain) obj).setUpdateTimeMark(updateTimeMark);
        }
        int result = getDao().updateByUpdateTime(obj);
        if (result == 0) {
            throw new DaoException(DaoExceptionEnum.DAO_UPDATE_ERROR);
        }
        afterUpdate(obj);
        return obj;
    }


    /**
     * 批量添加
     *
     * @param list
     * @return
     */
    public List<T> batchInsert(List<T> list) throws SkException {
        if (list == null || list.size() == 0) {
            return list;
        }
        getDao().batchInsert(list);
        return list;
    }


    public int batchDeleteBySearch(TS ts) throws SkException {
        return batchDeleteByList(getAllList(ts));
    }

    /**
     * 按map里的数据更新
     *
     * @param dataMap ，key 是字段名 value 要更新的数据
     * @return
     */
    public boolean updateDataBySearch(Map<String, Object> dataMap, TS search) throws SkException {
        try {
            if (search == null) {
                search = getSearchClass().newInstance();
            }

            if (search.updateTimeFiled() != null && !"".equals(search.updateTimeFiled())) {
                dataMap.put(search.updateTimeFiled(), new Date());
            }

            return getDao().updateDataBySearch(dataMap, search);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }
    }

    /**
     * 按map里的数据更新
     *
     * @param dataMap ，key 是字段名 value 要更新的数据
     * @return
     */


    public boolean updateDataById(Map<String, Object> dataMap, KeyType id) throws SkException {
        try {


            if (StringUtil.isNullOrEmpty(id)) {
                return false;
            }

            try {


                TS search = getSearchClass().newInstance();
                if (search.updateTimeFiled() != null && !"".equals(search.updateTimeFiled())) {
                    dataMap.put(search.updateTimeFiled(), new Date());
                }
            } catch (Exception e) {

            }

            return getDao().updateDataById(dataMap, id);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        }

    }


    public void fullSearchToListBySize(TS search){

    }

    public List<T> getListBySize(int size) {
        try {

            TS search = getSearchClass().newInstance();
            fullSearchToListBySize(search);

            if (size == -1) {
                return getAllList(search);
            }
            search.setPageNumber(1);
            search.setPageSize(size);
            return getList(search);
        } catch (Exception e) {
            return null;
        }
    }


    public void fullByLang(T t, String lang) {

        if (PageKeyEnum.LANG_CN.equalsIgnoreCase(lang)) {

            fullCn(t);


        } else if (PageKeyEnum.LANG_EN.equalsIgnoreCase(lang)) {

            fullEn(t);

        } else {
            fullOther(t);
        }


    }

    public void fullCn(T t) {

    }

    public void fullEn(T t) {

    }

    public void fullOther(T t) {


    }


    public List<T> getListBySizeAndLang(int size, String lang) {
        List<T> list = getListBySize(size);

        if (StringUtil.isNullOrEmpty(list)) {
            return null;
        }

        list.stream().forEach(item -> {
            fullByLang(item, lang);
        });
        return list;
    }


}
